<?php
/**
 * Oleksii Golub Packages
 * Copyright (C) 2012 Oleksii Golub <oleksii.golub@gmail.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

/**
 * @author Oleksii Golub <oleksii.golub@gmail.com>
 * @copyright Oleksii Golub 
 * @package Geo-Base
 * @version 1.0.0
 */
class Geo-Base {

    public function __construct($ip = false) {
        if (!function_exists('simplexml_load_string')) {
        	throw new Exception('Function simplexml_load_string() not exists', 0);
        }

        if (!function_exists('curl_init')) {
        	throw new Exception('Function curl_init() not exists', 0);
        }

        if (!$ip) {
            $ip = $this->_getIPCurrent();
        }
        $this->_ip = $ip;
    }


    /**
     * Функция возвращет конкретное значение из полученного массива данных по ip
     *
     * @param string $key - ключ массива, если интересует конкретное значение.
     * Ключ может быть равным 'inetnum', 'country', 'city', 'region', 'district', 'lat', 'lng'
     *
     * @param bolean $cookie - устанавливаем хранить данные в куки или нет
     * Если true, то в куки будут записаны данные по ip
     * и повторные запросы на ipgeobase происходить не будут.
     * Если false, то данные постоянно будут запрашиваться с ipgeobase
     *
     * @return mixed
     */
    public function getValue($key = false, $cookie = true) {
        $key_array = array('inetnum', 'country', 'city', 'region', 'district', 'lat', 'lng', 'ip');
        if (!in_array($key, $key_array)) {
            $key = false;
        }

        // если используем куки и параметр уже получен,
        // то достаем и возвращаем данные из куки
        if ($cookie && isset($_COOKIE['geobase'])) {
            $data = @unserialize(urldecode($_COOKIE['geobase']));
        } else {
            $data = $this->_getGeobaseData($this->_ip);
        }

        if ($cookie) {
            setcookie(
            'geobase',
            urlencode(serialize($data)),
            time()+3600*24*7  // устанавливаем куки на неделю
            );
        }

        if (!$data) {
            return false;
        }

        if ($key) {
            return @$data[$key];
        } else {
            return $data;
        }
    }

    /**
     * Функция получает данные по IP
     *
     * @param string $ip
     * @return array
     */
    private function _getGeobaseData($ip) {
        if (!empty($this->_dataArray[$ip])) {
        	return $this->_dataArray[$ip];
        }

        // получаем данные по ip
        $link = 'ipgeobase.ru:7020/geo?ip='.$ip;

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $link);
        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 1);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 1);
        $string = curl_exec($ch);

        if (!$string) {
            return false;
        }

        $xml = simplexml_load_string($string);
        $data = array();
        if ($xml)
            $data = array(
               'ip' => trim($xml->ip['value'].''),
               'inetnum' => trim($xml->ip->inetnum.''),
               'country' => trim($xml->ip->country.''),
               'city' => trim($xml->ip->city.''),
               'region' => trim($xml->ip->region.''),
               'district' => trim($xml->ip->district.''),
               'lat' => trim($xml->ip->lat.''),
               'lng' => trim($xml->ip->lng.''),
              );

        $this->_dataArray[$ip] = $data;

        return $data;
    }

    /**
     * функция определяет ip адрес по глобальному массиву $_SERVER
     * ip адреса проверяются начиная с приоритетного, для определения возможного использования прокси
     * @return ip-адрес
     */
    private function _getIPCurrent() {
        if ($this->_ipCurrent) {
            return $this->_ipCurrent;
        }

        if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            $ipa[] = trim(strtok($_SERVER['HTTP_X_FORWARDED_FOR'], ','));
        }

        if (isset($_SERVER['HTTP_CLIENT_IP'])) {
            $ipa[] = $_SERVER['HTTP_CLIENT_IP'];
        }

        if (isset($_SERVER['REMOTE_ADDR'])) {
            $ipa[] = $_SERVER['REMOTE_ADDR'];
        }

        if (isset($_SERVER['HTTP_X_REAL_IP'])) {
            $ipa[] = $_SERVER['HTTP_X_REAL_IP'];
        }

        // проверяем ip-адреса на валидность начиная с приоритетного.
        foreach($ipa as $ipx) {
            // если ip валидный обрываем цикл,
            // возвращаем его
            if ($this->CheckIP($ipx)) {
                $this->_ipCurrent = $ipx;
                return $ipx;
            }
        }

        return false;
    }

    private static function CheckIP($ip, $format = 'ipv4') {
        if ($format == 'ipv4') {
            $x = @long2ip(@ip2long($ip));
            if ($x == $ip) {
                return true;
            }
        } elseif ($format == 'ipv6') {
            if (preg_match('((^|:)([0-9a-fA-F]{0,4})){1,8}$', $ip)) {
                return true;
            }
        }
        return false;
    }
    
    /**
     * Кеш текущего IP
     *
     * @var string
     */
    private $_ipCurrent = false;

    private $_ip = false;

    private $_dataArray = array();

}